﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;
using System.Xml;
using System.Web;
using System.Xml.Linq;
using System.Runtime.Serialization;
using System.Xml.Serialization;
using Microsoft.Http;
using System.Web.Services;
using System.Configuration;

namespace Woodbase.CodeBase.WVR.Objects
{
    // Start the service and browse to http://<machine_name>:<port>/Service1/help to view the service's generated help page
    // NOTE: By default, a new instance of the service is created for each call; change the InstanceContextMode to Single if you want
    // a single instance of the service to process all calls.	
    [ServiceContract]
    [DataContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
    [XmlSerializerFormat]
    public class WVRService
    {
        XNamespace wvrm = XNamespace.Get("http://ns.woodbase.dk/Movies.xsd");
        XNamespace wvru = XNamespace.Get("http://ns.woodbase.dk/User.xsd");

        [WebGet(UriTemplate = "Movies")]
        [OperationContract]
        public List<Movie> GetMovies()
        {
            XDocument doc = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Movies.xml"));

            var nodes = doc.Descendants(wvrm + "movie");

            List<Movie> movielist = BuildMovieList(nodes);

            return movielist;
        }

        [WebGet(UriTemplate = "Movies/Rented")]
        [OperationContract]
        public List<Movie> GetRentedMovies()
        {
            List<Movie> movieList = new List<Movie>();
            XDocument doc = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Users.xml"));

            var nodes = doc.Descendants(wvru + "mymovie").Where(x => x.Attribute("rented").Value == "1").Descendants(wvrm + "movie");
            var mlist = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Movies.xml"));
            var mnodes = new XDocument(new XElement(wvrm + "rentedmovies"));


            foreach (var c in nodes)
            {
                mnodes.Root.Add(mlist.Descendants(wvrm + "movie").Where(x => x.Attribute("title").Value == c.Attribute("title").Value));
            }

            return BuildMovieList(mnodes.Descendants(wvrm + "movie"));
        }

        [WebGet(UriTemplate = "Genres")]
        [OperationContract]
        public List<Genre> GetGenres()
        {
            XDocument doc = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Movies.xml"));
            XNamespace ns = XNamespace.Get("http://ns.woodbase.dk/Movies.xsd");
            //[not(@manufacturer=preceding-sibling::car/@manufacturer)]/@manufacturer
            var nodeGroups = doc.Descendants(ns + "genre").GroupBy(x => x.Attribute("name").Value.ToLower());
            List<Genre> result = new List<Genre>();
            foreach (var g in nodeGroups)
            {
                result.Add(new Genre(){ Name = g.First().FirstAttribute.Value.ToString()});
            }
            
            return result;
        }

        [WebGet(UriTemplate = "Users")]
        public Users GetUsers()
        {
            var u = new Users();
            var doc = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Users.xml")).Descendants(wvru + "user");

            foreach (var n in doc)
            {
                var movies = n.Descendants(wvru + "movielist").Descendants(wvru + "mymovie").Descendants("{http://ns.woodbase.dk/Movies.xsd}movie");
                var movieList = new Movies();
                foreach (var m in movies)
                {
                    movieList.Add(new Movie() { MTitle = m.Attribute("title").Value });
                }

                u.Add(new User()
                {
                    GivenName = n.Attribute("givenname").Value,
                    LastName = n.Attribute("lastname").Value,
                    Active = (n.Attribute("active").Value.ToLower() == "false" || n.Attribute("active").Value == "0") ? false : true,
                    Blacklisted = (n.Attribute("blacklisted").Value.ToLower() == "false" || n.Attribute("blacklisted").Value == "0") ? false : true,
                    Street = n.Attribute("street").Value,
                    Number = n.Attribute("streetnumber").Value,
                    ZipCode = n.Attribute("zipcode").Value,
                    City = n.Attribute("city").Value,
                    Phone = n.Attribute("phone").Value,
                    UserId = n.Attribute("userid").Value,
                    Movies = movieList
                });
            }

            return u;
        }

        [WebGet(UriTemplate = "User/{userid}")]
        public User GetUser(string userid)
        {
            User temp = new User();

            XElement userNode = (XElement)XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Users.xml")).Descendants(wvru + "user").Select(x => x.Attribute("userid").Value == userid);

            temp.GivenName = userNode.Attribute("givenname").Value;
            temp.LastName = userNode.Attribute("lastname").Value;
            temp.Active = (userNode.Attribute("active").Value.ToLower() == "false" || userNode.Attribute("active").Value == "0") ? false : true;
            temp.Blacklisted = (userNode.Attribute("blacklisted").Value.ToLower() == "false" || userNode.Attribute("blacklisted").Value == "0") ? false : true;
            temp.Street = userNode.Attribute("street").Value;
            temp.Number = userNode.Attribute("streetnumber").Value;
            temp.ZipCode = userNode.Attribute("zipcode").Value;
            temp.City = userNode.Attribute("city").Value;
            temp.Phone = userNode.Attribute("phone").Value;
            temp.UserId = userNode.Attribute("userid").Value;

            return temp;
        }

        [WebInvoke(UriTemplate = "Actors", Method = "GET")]
        public List<Actor> GetAllActors()
        {
            List<Actor> actors = new List<Actor>();
            XNamespace ns = XNamespace.Get("http://ns.woodbase.dk/Movies.xsd");
            XDocument doc = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Actors.xml"));
            var t = doc.Descendants(ns + "actor").Select(x => new Actor() { GivenName = x.Attribute("givenName").Value, LastName = x.Attribute("lastName").Value, BirthYear = int.Parse(x.Attribute("birthYear").Value), Nationality = x.Attribute("nationality").Value });
            actors.AddRange(t);

            return actors;
        }

        [WebInvoke(UriTemplate = "Actor/{actorName}", Method = "GET")]
        public Actor GetActors(string actorName)
        {
            var aname = HttpUtility.UrlDecode(actorName);
            XNamespace ns = XNamespace.Get("http://ns.woodbase.dk/Movies.xsd");
            XDocument doc = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Actors.xml"));
            var t = doc.Descendants(ns + "actor").Select(x => new Actor() { GivenName = x.Attribute("givenName").Value, LastName = x.Attribute("lastName").Value, BirthYear = int.Parse(x.Attribute("birthYear").Value), Nationality = x.Attribute("nationality").Value });
            var tt = t.Where(x => x.GivenName.Contains(aname.Split(' ')[0]) && x.LastName.Contains(aname.Split(' ')[aname.Split(' ').Length - 1])).First();
            return tt;
        }

        [WebInvoke(UriTemplate = "Actor", Method = "PUT")]
        public void AddActor(Actor actor)
        {
            XDocument actors = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Actors.xml"));
            actors.Root.Add(actor.ToXml());
            actors.Save(HttpContext.Current.Server.MapPath("~/Data/Actors.xml"));
        }

        [WebInvoke(UriTemplate = "User", Method = "PUT")]
        public bool AddUser(User user)
        {
            XDocument doc = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Users.xml"));
            var latestUserID = doc.Descendants("{http://ns.woodbase.dk/User.xsd}user").OrderBy(x => x.Attribute("userid").Value).Last().Attribute("userid").Value;
            var nuid = latestUserID.Split('-');
            user.UserId = nuid[0] + "-" + (int.Parse(nuid[1]) + 1).ToString("D4");
            doc.Root.Add(user.ToXml());
            doc.Save(HttpContext.Current.Server.MapPath("~/Data/Users.xml"));
            return true;
        }

        [WebInvoke(UriTemplate = "User/{userid}/Movie/Rent/{movielist}", Method = "POST")]
        public bool RentMovies(string userid, string movielist)
        {
            XNamespace uns = XNamespace.Get("http://ns.woodbase.dk/User.xsd");
            XDocument movieDoc = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Movies.xml"));
            XDocument userDoc = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Users.xml"));

            var rentedMovies = movieDoc.Descendants("{http://ns.woodbase.dk/Movies.xsd}movie").Where(x => movielist.Split(';').Contains(x.Attribute("title").Value)).Select(x => x);
            var user = userDoc.Descendants(uns + "user").Where(x => x.Attribute("userid").Value == userid).Select(x => x);

            if (user.Descendants(uns + "movielist") == null)
            {
                user.First().Add(new XElement(uns + "movielist"));
            }
            XElement newRental = new XElement(uns + "mymovie", new XAttribute("rented", 1), new XAttribute("returndate", DateTime.Now.AddDays(int.Parse(ConfigurationManager.AppSettings["rentPeriodLength"])).ToString("yyyy-MM-dd")), rentedMovies);
            user.Descendants(uns + "movielist").First().Add(newRental);
            userDoc.Save(HttpContext.Current.Server.MapPath("~/Data/Users.xml"));
            return true;
        }
        
        [WebInvoke(UriTemplate = "Movie", Method = "PUT")]
        public Movie AddMovie(Movie movie)
        {
            XDocument doc = XDocument.Load(HttpContext.Current.Server.MapPath("~/Data/Movies.xml"));
            doc.Root.Add(movie.ToXml());
            doc.Save(HttpContext.Current.Server.MapPath("~/Data/Movies.xml"));
            return movie;
        }



     

       
        //[WebInvoke(UriTemplate = "", Method = "POST")]
        //public SampleItem Create(SampleItem instance)
        //{
        //    // TODO: Add the new instance of SampleItem to the collection
        //    throw new NotImplementedException();
        //}

        //[WebGet(UriTemplate = "{id}")]
        //public SampleItem Get(string id)
        //{
        //    // TODO: Return the instance of SampleItem with the given id
        //    throw new NotImplementedException();
        //}

        //[WebInvoke(UriTemplate = "{id}", Method = "PUT")]
        //public SampleItem Update(string id, SampleItem instance)
        //{
        //    // TODO: Update the given instance of SampleItem in the collection
        //    throw new NotImplementedException();
        //}

        //[WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
        //public void Delete(string id)
        //{
        //    // TODO: Remove the instance of SampleItem with the given id from the collection
        //    throw new NotImplementedException();
        //}


        private List<Movie> BuildMovieList(IEnumerable<XElement> nodes)
        {
            List<Movie> movielist = new List<Movie>();
            foreach (var current in nodes)
            {
                List<Actor> actorlist = new List<Actor>();

                foreach (var actor in current.Descendants(wvrm + "actor"))
                {
                    Gender aGender;

                    if (actor.Attribute("male").Value.Length == 1)
                    {
                        aGender = (Convert.ToBoolean(int.Parse(actor.Attribute("male").Value.ToUpper())) == true) ? Gender.MALE : Gender.FEMALE;
                    }
                    else
                    {
                        //TODO: Look for solution to converting lower case false to boolean
                        //Stupid quirk in .Net - can't convert 'false' to boolean, only 'False' can be converted
                        aGender = (actor.Attribute("male").Value.ToLower() == "true") ? Gender.MALE : Gender.FEMALE;
                    }
                    actorlist.Add(new Actor() { GivenName = actor.Attribute("givenName").Value, LastName = actor.Attribute("lastName").Value, BirthYear = (actor.Attribute("birthYear") != null) ? int.Parse(actor.Attribute("birthYear").Value) : 0, Sex = aGender });
                }

                List<Genre> genreList = new List<Genre>();
                foreach (var genre in current.Descendants(wvrm + "genre"))
                {
                    genreList.Add(new Genre() { Name = genre.Attribute("name").Value });
                }


                var coverImage = (current.Descendants(wvrm + "image").Any() == true) ? current.Descendants(wvrm + "image").First().Attribute("coverFront").Value : "";
                //var backImage = (current.Descendants(wvrm + "image").Any() == true) ? (current.Descendants(wvrm + "image").First().Attribute("backCover").Value != null ? current.Descendants(wvrm + "image").First().Attribute("backCover").Value : "") : "";

                var images = new List<string>();

                if (current.Descendants(wvrm + "img").Any())
                {
                    foreach (var img in current.Descendants(wvrm + "image").First().Descendants(wvrm + "img"))
                    {
                        images.Add(img.Value);
                    }
                }
                movielist.Add(new Movie()
                {
                    MTitle = current.Attribute("title").Value,
                    PlayTime = int.Parse(current.Attribute("playtime").Value),
                    ProductionYear = int.Parse(current.Attribute("year").Value),
                    CoverFront = coverImage,
                    //CoverBack = backImage,
                    Images = images,
                    Actors = actorlist,
                    Genres = genreList
                });
            }
            return movielist;
        }

    }
}
